<?php


namespace EchoPHP\Validator\Rules;


use EchoPHP\File\UploadedFile;
use EchoPHP\Validator\Rule;
use EchoPHP\Validator\ValidateAttribute;

class Dimensions implements Rule {

    use ValidateAttribute;

    protected $constraints = [];
    protected $message;
    protected $customMessage;
    protected $attributeTitle;

    public function __construct(array $constraints = []) {
        $this->constraints = $constraints;
    }

    /**
     * 验证图片宽度
     * @param $value
     * @return $this
     */
    public function width($value) {
        $this->constraints['width'] = $value;
        return $this;
    }

    /**
     * 验证图片高度
     * @param $value
     * @return $this
     */
    public function height($value) {
        $this->constraints['height'] = $value;
        return $this;
    }

    /**
     * 验证图片最小宽度
     * @param $value
     * @return $this
     */
    public function minWidth($value) {
        $this->constraints['min_width'] = $value;
        return $this;
    }

    /**
     * 验证图片最大宽度
     * @param $value
     * @return $this
     */
    public function maxWidth($value) {
        $this->constraints['max_width'] = $value;
        return $this;
    }

    /**
     * 验证图片最小高度
     * @param $value
     * @return $this
     */
    public function minHeight($value) {
        $this->constraints['min_height'] = $value;
        return $this;
    }

    /**
     * 验证图片最大高度
     * @param $value
     * @return $this
     */
    public function maxHeight($value) {
        $this->constraints['max_height'] = $value;
        return $this;
    }

    /**
     * 验证图片宽高比
     * @param $value
     * @return $this
     */
    public function ratio($value) {
        $this->constraints['ratio'] = $value;
        return $this;
    }

    /**
     * 自定义错误消息
     * @param string $message
     * @return $this
     */
    public function setMessage(string $message) {
        $this->customMessage = $message;
        return $this;
    }

    /**
     * @inheritDoc
     */
    public function validate($attribute, $attributeTitle, $value, array $data) {
        $this->attributeTitle = $attributeTitle;
        /**
         * @var UploadedFile $value
         */
        if ($this->isValidFileInstance($value) && $value->getClientMimeType() === 'image/svg+xml') {
            return true;
        }

        if (!$this->isValidFileInstance($value) || !$imageSize = @getimagesize($value->getRealPath())) {
            $this->message = ':attribute不是一个正确的图片文件';
            return false;
        }
        [$width, $height] = $imageSize;

        return $this->checkBasicDimensions($width, $height);
    }

    /**
     * 基础尺寸校验
     * @param $width
     * @param $height
     * @return bool
     */
    protected function checkBasicDimensions($width, $height) {
        if (isset($this->constraints['width']) && $this->constraints['width'] != $width) {
            $this->message = ':attribute宽度必须等于[' . $this->constraints['width'] . ']px';
            return false;
        } elseif (isset($this->constraints['min_width']) && $this->constraints['min_width'] > $width) {
            $this->message = ':attribute宽度必须不小于[' . $this->constraints['min_width'] . ']px';
            return false;
        } elseif (isset($this->constraints['max_width']) && $this->constraints['max_width'] < $width) {
            $this->message = ':attribute宽度必须不大于[' . $this->constraints['max_width'] . ']px';
            return false;
        } elseif (isset($this->constraints['height']) && $this->constraints['height'] != $height) {
            $this->message = ':attribute高度必须等于[' . $this->constraints['height'] . ']px';
            return false;
        } elseif (isset($this->constraints['min_height']) && $this->constraints['max_height'] > $height) {
            $this->message = ':attribute高度必须不小于[' . $this->constraints['max_height'] . ']px';
            return false;
        } elseif (isset($this->constraints['max_height']) && $this->constraints['max_height'] < $height) {
            $this->message = ':attribute高度必须不大于[' . $this->constraints['max_height'] . ']px';
            return false;
        }
        if (!isset($this->constraints['ratio'])) {
            return true;
        }
        [$numerator, $denominator] = array_replace(
            [1, 1], array_filter(sscanf($this->constraints['ratio'], '%f/%d'))
        );


        $precision = 1 / max($width, $height);

        if (abs($numerator / $denominator - $width / $height) > $precision) {
            $this->message = ':attribute的宽高比应该等于[' . number_format($this->constraints['ratio'], '3') . '/1]';
            return false;
        }
        return true;
    }

    /**
     * @inheritDoc
     */
    public function message() {
        $message = $this->customMessage ?: $this->message;
        return str_replace(':attribute', $this->attributeTitle, $message);
    }


}